import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:lrc/lrc.dart';

import 'player.dart';
import 'player_android.dart';
import 'types.dart';

class ArticlePage extends StatefulWidget {
  final TeachingFiles cls;
  const ArticlePage({super.key, required this.cls});

  @override
  State<ArticlePage> createState() => _ArticlePageState();
}

Future<Lrc> parseLrc(String assetsName) async {
  var lrcString = await rootBundle.loadString(assetsName);
  return Lrc.parse(lrcString);
}

class LineWithId {
  final int id;
  final LrcLine line;

  LineWithId(this.id, this.line);
}

class _ArticlePageState extends State<ArticlePage> {
  Lrc? _lrc;
  Timer? _timer;
  bool _isPlaying = false;
  final player = Platform.isAndroid
      ? MyAudioPlayerJustAudio()
      : MyAudioPlayer();

  @override
  void initState() {
    super.initState();
    player
        .initAssets(widget.cls.mp3Path)
        .then((_) {
          // player.setPlayerMode(PlayerMode.lowLatency);
          print('Audio loaded successfully');
        })
        .catchError((e) {
          print('Error loading audio: $e');
          ScaffoldMessenger.of(
            context,
          ).showSnackBar(SnackBar(content: Text('Failed to load audio')));
        });

    parseLrc(widget.cls.lrcPath)
        .then((r) {
          setState(() {
            _lrc = r;
          });
          print('LRC loaded successfully');
        })
        .catchError((e) {
          print('Error loading LRC: $e');
          ScaffoldMessenger.of(
            context,
          ).showSnackBar(SnackBar(content: Text('Failed to load lyrics')));
        });
  }

  @override
  void dispose() {
    super.dispose();
    player.dispose();
  }

  Lrc get lrc {
    if (_lrc == null) {
      throw Exception('LRC not loaded');
    }
    return _lrc!;
  }

  List<LineWithId> get allLines {
    if (_lrc == null) {
      return [];
    }

    final List<LineWithId> rs = [];
    for (int i = 0; i < lrc.lyrics.length; i++) {
      var line = lrc.lyrics[i];
      rs.add(LineWithId(i, line));
    }
    return rs;
  }

  List<LineWithId> get linesWithoutEmpty {
    if (_lrc == null) {
      return [];
    }

    final List<LineWithId> rs = [];
    for (int i = 0; i < lrc.lyrics.length; i++) {
      var line = lrc.lyrics[i];
      if (line.lyrics.trim().isNotEmpty) {
        rs.add(LineWithId(i, line));
      }
    }
    return rs;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.cls.title),
        actions: [
          IconButton(
            icon: Icon(_isPlaying ? Icons.pause : Icons.play_arrow),
            onPressed: () {
              if (_isPlaying) {
                pause();
              } else {
                playAll();
              }
            },
          ),
        ],
      ),
      body: ListView.builder(
        itemCount: linesWithoutEmpty.length,
        itemBuilder: (context, index) {
          final line = linesWithoutEmpty[index];
          return ListTile(
            title: Text(line.line.lyrics),
            onTap: () {
              playLine(index);
            },
          );
        },
      ),
    );
  }

  void playLine(int pos) async {
    if (player.state == MyPlayerState.playing) {
      await player.pause();
      if (_timer != null) {
        _timer!.cancel();
        _timer = null;
      }
    }

    var startPos = pos;
    final lines = linesWithoutEmpty;
    if (startPos < 0 || startPos >= lines.length) {
      print('Invalid position: $startPos');
      return;
    }

    var startTime = lines[startPos].line.timestamp;
    await player.seek(lines[pos].line.timestamp);
    player.resume();
    setPlaying(true);

    // find the next line from allLines
    final nextLine = getNextLine(allLines, lines[startPos].id);
    if (nextLine == null) {
      print('No next line found');
      return;
    }

    var endTime = nextLine.line.timestamp;
    print('Playing from $startTime to $endTime');

    _timer = Timer(endTime - startTime, () async {
      print('Stopping after ${endTime - startTime} milliseconds');
      await player.pause();
      setPlaying(false);
    });
  }

  void setPlaying(bool playing) {
    setState(() {
      _isPlaying = playing;
    });
  }

  void playAll() async {
    if (player.state == MyPlayerState.playing) {
      await player.pause();
      if (_timer != null) {
        _timer!.cancel();
        _timer = null;
      }
    }

    player.seek(Duration.zero);
    player.resume();
    setPlaying(true);
  }

  void pause() async {
    await player.pause();
    setPlaying(false);
    if (_timer != null) {
      _timer!.cancel();
      _timer = null;
    }
  }
}

LineWithId? getNextLine(List<LineWithId> lines, int lineId) {
  for (var i = 0; i < lines.length; i++) {
    if (lines[i].id == lineId) {
      if (i + 1 < lines.length) {
        return lines[i + 1];
      } else {
        // No next line
        return null;
      }
    }
  }
  return null;
}
